package com.peng.rpc.common.server;

import com.peng.rpc.entity.RpcRequest;
import com.peng.rpc.entity.RpcResponse;
import com.peng.rpc.enumeration.ResponseCode;
import com.peng.rpc.enumeration.RpcError;
import com.peng.rpc.exception.RpcException;
import com.peng.rpc.provider.DefaultServiceProvider;
import com.peng.rpc.provider.ServiceProvider;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 服务器根据方法和类型反射调用方法
 * @author Wonderson
 * @email wpp.ds@foxmail.com
 * @date 2022/2/28 20:11
 */
@Slf4j
public class RequestHandler {

    private static final ServiceProvider serviceProvider;

    private RequestHandler() {

    }

    static {
        serviceProvider = new DefaultServiceProvider();
    }

    public Object handle(RpcRequest rpcRequest) {
        Object result;
        try {
            result = invokeTargetMethod(rpcRequest);
            log.info("service：{}调用方法：{} 成功", rpcRequest.getInterfaceName(), rpcRequest.getMethodName());
        } catch (InvocationTargetException | IllegalAccessException e) {
            log.info("没有找到要调用的方法：{}", rpcRequest.getMethodName());
            return RpcResponse.fail(ResponseCode.NOT_FOUND_METHOD, rpcRequest.getRequestId());
        }
        return result;
    }

    /**
     * 按照请求对象提供的信息和对应的实体类来执行请求方法
     */
    private Object invokeTargetMethod(RpcRequest rpcRequest) throws InvocationTargetException, IllegalAccessException {
        String serviceName = rpcRequest.getInterfaceName();
        Object service = serviceProvider.getService(serviceName);
        Class<?> clazz = service.getClass();
        Method method;
        try {
            method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getParamTypes());
        } catch (NoSuchMethodException e) {
            throw new RpcException(RpcError.SERVICE_NO_INTERFACE);
        }
        return method.invoke(service, rpcRequest.getParameters());
    }

}
